package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.AroundSign;
import com.myk.game.gobangchess.signs.ColorSign;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.LineSign;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 迫移
 */
public class ForceKingMoveRoom extends Room {

    private int[] lastPoint; //上一步落子的位置  row，col
    private int[] curPoint; //该回合落子位置  row，col
    private int[] choosePoint; //当前选中要移动的棋子坐标  row，col
    private List<int[]> forceKingMoveList; //要被强制移动的棋子坐标集合
    private List<Integer> forcePosList; //要被强制移动的位置坐标集合
    private final List<int[]> moveArrayList = new ArrayList<>(); // 棋子移动标记

    public ForceKingMoveRoom(String roomName) {
        super(roomName, "逆界群友小紫设计的新棋", "迫移", GridsUtils.createEmptyGrids(10,10), true, true);
    }

    @Override
    public String getRuleText() {
        return "10*10棋盘，黑白双方轮流落子，\n" +
                "若己方刚落下的棋子，与对方刚落下的棋子在同一条直线或斜线，则己方将这二子之间的棋子逐一选择并移出这条线外，需按国象“王”的走法移动。\n" +
                "在任何情况下，只要达成以下条件，立即判定胜负\n" +
                "获胜条件：己方棋子形成五子连珠\n" +
                "失败条件：己方棋子被选择且无法被移动\n" +
                "和棋条件：棋盘下满时，若无连五，立即和棋，不管是否需要移动棋子";
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        lastPoint = null;
        curPoint = null;
        choosePoint = null;
        forceKingMoveList = null;
        forcePosList = null;
        moveArrayList.clear();
    }

    @Override
    public String getGameInfo() {
        //先清空棋盘
        signList.clear();
        //画上次落子框
        if (lastPoint != null){
            signList.add(new AroundSign(getIndex(lastPoint[0],lastPoint[1]),"#00000000","#6600FF00",1.2f));
        }
        //画当前落子框
        if (curPoint != null){
            signList.add(new AroundSign(getIndex(curPoint[0],curPoint[1]),"#00000000","#6600FF00",1.2f));
            //画禁止落子线
            if (forcePosList != null && forcePosList.size() > 0){
                signList.add(new ColorSign(forcePosList, "#66333333"));
            }
        }
        //画棋子选中框
        if (choosePoint != null){
            signList.add(new GroundSign(getIndex(choosePoint[0], choosePoint[1]), "#00FFFFFF", "#FF33CC33", 2F, 0, 1));
            List<Integer> aroundRange = getAroundRange(choosePoint[0], choosePoint[1]);
            if (aroundRange.size() > 0){
                signList.add(new ColorSign(aroundRange, "#6633CC33"));
            }
        }
        //画移动箭头
        for (int[] moveArray : moveArrayList) {
            signList.add(new LineSign(moveArray[0], moveArray[1], ColorCost.MOVE_ARROW_LIGHT, 1));
        }
        return super.getGameInfo();
    }

    @Override
    public void doRule(int row, int col, int value) {
        //当前有要被迫移的棋子时
        if (forceKingMoveList!=null && forceKingMoveList.size()>0){
            //当前有选中的棋子时
            if (choosePoint != null){
                if (getAroundRange(choosePoint[0], choosePoint[1]).contains(getIndex(row,col))){
                    moveArrayList.add(new int[]{getIndex(choosePoint[0], choosePoint[1]),getIndex(row,col)});
                    curGrids[row][col] = curGrids[choosePoint[0]][choosePoint[1]];
                    curGrids[choosePoint[0]][choosePoint[1]] = 0;
                    forceKingMoveList.removeIf(point -> point[0] == choosePoint[0] && point[1] == choosePoint[1]);
                    choosePoint = null;
                    if (checkFormation(value, 5) > 0){
                        if (value == 1){
                            stepAdd();
                            doOver(WinMode.BLACK_WIN, "黑方形成五子连珠获胜");
                        }
                        else {
                            stepAdd();
                            doOver(WinMode.WHITE_WIN, "白方形成五子连珠获胜");
                        }
                    }
                    else {
                        if (forceKingMoveList.size()>0){
                            if (hasCantMoveForceKing(value)){
                                if (value == 1){
                                    stepAdd();
                                    doOver(WinMode.WHITE_WIN, "黑方有棋子要迫移，但是没法移动，白方获胜");
                                }
                                else {
                                    stepAdd();
                                    doOver(WinMode.BLACK_WIN, "白方有棋子要迫移，但是没法移动，黑方获胜");
                                }
                            }
                            else if (hasCantMoveForceKing(3-value)){
                                if (value == 1){
                                    stepAdd();
                                    doOver(WinMode.BLACK_WIN, "白方有棋子要迫移，但是没法移动，黑方获胜");
                                }
                                else {
                                    stepAdd();
                                    doOver(WinMode.WHITE_WIN, "黑方有棋子要迫移，但是没法移动，白方获胜");
                                }
                            }
                            else {
                                noticeAllRefreshGameInfo();
                            }
                        }
                        else {
                            lastPoint = curPoint;
                            curPoint = null;
                            changeMover(value);
                        }
                    }
                }
            }
            //没有选中的棋子时
            else {
                if (isChooseForce(row, col)){
                    choosePoint = new int[]{row,col}; //选中要移动的棋子
                    noticeAllRefreshGameInfo();
                }
            }
        }
        //没有迫移棋子，正常落子时
        else {
            if (curGrids[row][col] != 0) return;
            curGrids[row][col] = value;
            curPoint = new int[]{row,col};
            moveArrayList.clear();
            if (checkFormation(value, 5) > 0){
                if (value == 1){
                    stepAdd();
                    doOver(WinMode.BLACK_WIN, "黑方形成五子连珠获胜");
                }
                else {
                    stepAdd();
                    doOver(WinMode.WHITE_WIN, "白方形成五子连珠获胜");
                }
            }
            else {
                //检查是否平局
                if (GridsUtils.getDataCount(curGrids, 0) == 0){
                    doOver(WinMode.BOTH_DRAW, "棋盘下满，没有形成连珠，和棋");
                    return;
                }
                //检查是否夹住了棋子
                if (checkSideKing(row,col)) {
                    //存在己方要迫移但是没法移动的棋子时
                    if (hasCantMoveForceKing(value)){
                        if (value == 1){
                            stepAdd();
                            doOver(WinMode.WHITE_WIN, "黑方有棋子要迫移，但是没法移动，白方获胜");
                        }
                        else {
                            stepAdd();
                            doOver(WinMode.BLACK_WIN, "白方有棋子要迫移，但是没法移动，黑方获胜");
                        }
                        return;
                    }
                    else if (hasCantMoveForceKing(3 - value)){
                        if (value == 1){
                            stepAdd();
                            doOver(WinMode.BLACK_WIN, "白方有棋子要迫移，但是没法移动，黑方获胜");
                        }
                        else {
                            stepAdd();
                            doOver(WinMode.WHITE_WIN, "黑方有棋子要迫移，但是没法移动，白方获胜");
                        }
                        return;
                    }
                    noticeAllRefreshGameInfo();
                    return;
                }
            }
            lastPoint = new int[]{row,col};
            curPoint = null;
            changeMover(value);
        }
    }

    //存在己方要迫移但是没法移动的棋子时
    private boolean hasCantMoveForceKing(int value) {
        for (int[] ints : this.forceKingMoveList) {
            if (curGrids[ints[0]][ints[1]] == value && getAroundRange(ints[0],ints[1]).size() == 0) return true;
        }
        return false;
    }

    //该位置在被迫移棋子列表中
    private boolean isChooseForce(int row, int col) {
        for (int[] ints : forceKingMoveList) {
            if (ints[0] == row && ints[1] == col) return true;
        }
        return false;
    }

    //检查是否夹住了棋子
    private boolean checkSideKing(int row, int col) {
        if (isSameLine(row,col)){
            updPointsInLine(row,col);
            return this.forceKingMoveList.size() > 0;
        }
        return false;
    }

    //获取当前落子位置周围的空格坐标集合
    public List<Integer> getAroundRange(int row, int col){
        int[][] dxdys = {{-1,-1}, {-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
        List<Integer> rangeIndex = new ArrayList<>();
        for (int[] dxdy : dxdys) {
            int x = row + dxdy[0];
            int y = col + dxdy[1];
            if (x >= 0 && x < curGrids.length && y >= 0 && y < curGrids[0].length && curGrids[x][y] == 0){
                if (forcePosList != null && forcePosList.contains(getIndex(x, y))) continue;
                rangeIndex.add(getIndex(x, y));
            }
        }
        return rangeIndex;
    }

    //获取指定落点和上一个落点之前的棋子集合
    private void updPointsInLine(int row, int col) {
        this.forceKingMoveList = new ArrayList<>();
        this.forcePosList = new ArrayList<>();
        int rowAdd = Integer.compare(row, lastPoint[0]);
        int colAdd = Integer.compare(col, lastPoint[1]);
        for (int i = lastPoint[0],j = lastPoint[1]; i != row || j != col; i += rowAdd, j += colAdd){
            if (i == lastPoint[0] && j == lastPoint[1]){
                continue;
            }
            if (curGrids[i][j] != 0){
                this.forceKingMoveList.add(new int[]{i,j});
            }
            forcePosList.add(getIndex(i, j));
        }
    }

    //判断指定落点和对方上一步的坐标是否直线斜线共线
    private boolean isSameLine(int row, int col) {
        if (lastPoint != null) {
            return lastPoint[0] == row || lastPoint[1] == col || Math.abs(row - lastPoint[0]) == Math.abs(col - lastPoint[1]);
        }
        return false;
    }

    private void changeMover(int value) {
        if (value == 1) {
            stepAdd();
            noticeWhiteMove();
        } else if (value == 2) {
            stepAdd();
            noticeBlackMove();
        }
    }

    private int checkFormation(int value, int winLength) {
        int rows = curGrids.length;
        int cols = curGrids[0].length;
        int formationCount = 0;

        // 水平方向
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols - winLength + 1; j++) {
                int length = 0;
                for (int k = j; k < j + winLength; k++) {
                    if (curGrids[i][k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= winLength) {
                    formationCount += (length - winLength + 1);
                }
            }
        }

        // 垂直方向
        for (int i = 0; i < rows - winLength + 1; i++) {
            for (int j = 0; j < cols; j++) {
                int length = 0;
                for (int k = i; k < i + winLength; k++) {
                    if (curGrids[k][j] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= winLength) {
                    formationCount += (length - winLength + 1);
                }
            }
        }

        // 左上到右下方向
        for (int i = 0; i < rows - winLength + 1; i++) {
            for (int j = 0; j < cols - winLength + 1; j++) {
                int length = 0;
                for (int k = 0; k < winLength; k++) {
                    if (curGrids[i + k][j + k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= winLength) {
                    formationCount += (length - winLength + 1);
                }
            }
        }

        // 右上到左下方向
        for (int i = 0; i < rows - winLength + 1; i++) {
            for (int j = winLength - 1; j < cols; j++) {
                int length = 0;
                for (int k = 0; k < winLength; k++) {
                    if (curGrids[i + k][j - k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= winLength) {
                    formationCount += (length - winLength + 1);
                }
            }
        }

        return formationCount;
    }

    protected int getJudgeLength(int x, int y, int dx, int dy) {
        int value = curGrids[x][y];
        int length = 0;
        while (isInGrids(x, y)) {
            if (curGrids[x][y] != value) {
                return length;
            }
            length++;
            x += dx;
            y += dy;
        }
        return length;
    }

    // 判断位置在棋盘上
    protected boolean isInGrids(int row, int col) {
        return row >= 0 && row <= curGrids.length - 1 && col >= 0 && col <= curGrids[0].length - 1;
    }
}
